package com.sky.service.impl;

import com.sky.controller.admin.WorkspaceController;
import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrdersMapper;
import com.sky.mapper.UserMapper;
import com.sky.result.Result;
import com.sky.service.ReportService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.aspectj.lang.annotation.AfterReturning;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private UserMapper userMapper;

    /**
     * 营业额数据统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO getTurnover(LocalDate begin, LocalDate end) {
        //创建dateList日期对象
        ArrayList<LocalDate> dateList = new ArrayList<>();
        //把当天的日期进行添加
        dateList.add(begin);
        //进行判断，开始的时间到结束的时间有多少天
        while (begin.isBefore(end)){
            //有几天就往集合里添加几天
            begin = begin.plusDays(1);
            //增加一天添加到集合
            dateList.add(begin);
        }

        //创建一个营业额对象turnoverList
        ArrayList<Double> amount = new ArrayList<>();
        //遍历日期集合获取到每天的日期，查询每天日期的营业额
        for (LocalDate date : dateList) {
            //获取到了当天的日期，我们设置当天的开始时间和结束时间
            //当日最小的时间
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            //当日最后的时间
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);

            //我们可以把这些数据存到集合中在map层去查询
            Map<String , Object> map = new HashMap<>();
            map.put("endTime",endTime);
            map.put("beginTime",beginTime);
            map.put("status", Orders.COMPLETED);

            //进入mapper层去查询，返回总营业额
            Double ordersAmount = ordersMapper.getByMapOrders(map);
            amount.add(ordersAmount);
        }
        //封装返回
        StringJoiner sb = new StringJoiner(",");
        StringJoiner sb1 = new StringJoiner(",");
        //遍历那两个集合今天封装成字符串
        for (LocalDate localDate : dateList) {
            sb.add(localDate.toString());
        }
        for (Double aDouble : amount) {
            if (aDouble == null ||aDouble == 0){
                sb1.add("0");
            }else {
                sb1.add(aDouble.toString());
            }
        }

        return new TurnoverReportVO(sb.toString(),sb1.toString());
    }
    /**
     * 用户数据统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO UserStatistics(LocalDate begin, LocalDate end) {
        //前端返回需要日期列表、新增用户数列表、总用户量列表
        //我们先获取前端传来的日期封装到集合里
        List<LocalDate> localDates = new ArrayList<>();
        //添加当前开始日期的元素
        localDates.add(begin);
        //进行循环，判断开始时间到结束时间有多少天
        while (begin.isBefore(end)){
            //只要开始时间和结束时间不相等就给开始时间+1天，添加到集合
            begin = begin.plusDays(1);
            localDates.add(begin);
        }
        //创建新增用户数列表
        List<Integer> newUsers = new ArrayList<>();
        //创建总用户量列表
        List<Integer> totalUserList= new ArrayList<>();

        //根据日期和订单去查询用户的新增数量.我们形参设置两个日期属性
        for (LocalDate date : localDates) {
            //我们获取到前段给我们传来的每天的日期
            //跟上一个功能一样，我们获取到当天的最开始时间和最后时间
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
            //调用mapper层查找当前的新增用户
            Integer count = userMapper.selectUser(beginTime,endTime);
            newUsers.add(count);

            Integer TotalUsers = userMapper.selectUser(null,LocalDateTime.now());
            totalUserList.add(TotalUsers);
        }
        String pjoin1 = pjoin(localDates);
        String pjoin2 = pjoin(newUsers);
        //这里我们使用StringUtils来进行集合转换为字符串格式
        return new UserReportVO(pjoin1,StringUtils.join(totalUserList, ","),pjoin2);
//        return new UserReportVO(StringUtils.join(localDates,",")
//                                ,StringUtils.join(totalUserList, ",")
//                                ,StringUtils.join(newUsers,","));
    }

    /**
     * 订单统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        //日期列表，以逗号分隔
        //创建日期集合
        List<LocalDate> localDates = new ArrayList<>();
        //添加日期到集合中
        localDates.add(begin);
        //进行循环判断，如果开始日期和结束日期不相等就给开始日期+1天，并添加到集合中
        while (begin.isBefore(end)){
            begin = begin.plusDays(1);
            localDates.add(begin);
        }
        //查询有效订单数的添加到集合列表
        List<Integer> validOrderCountList = new ArrayList<>();

        //查询每天的订单数，添加到集合列表
        List<Integer> orderCountList = new ArrayList<>();
        //遍历前端传来的日期
        for (LocalDate date : localDates) {
            //设置当天开始日期和结束日期
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
            //查询到每天的订单数，添加到集合中
            List<Orders> orders = getStringObjectMap(beginTime, endTime, null);
            log.info("里面的参数是:{}",orders);
            orderCountList.add(orders.size());
            //查询每天的有效订单数
            List<Orders> orders1 = getStringObjectMap(beginTime,endTime,Orders.COMPLETED);
            //添加每天的有效订单数
            validOrderCountList.add(orders1.size());


        }
        Integer total = 0;
        //添加订单总数
        for (Integer integer : orderCountList) {
            total += integer;
        }
        //查询设置有效订单数的总数
        Integer effective = 0;
        for (Integer integer : validOrderCountList) {
            effective += integer;
        }

        //添加订单完成率：有效订单数 / 总订单数
//        Double CompletionRate = 0.0;
//        if(CompletionRate != 0){
//            CompletionRate = effective.doubleValue() / total;
//        }
        double CompletionRate = new BigDecimal((float)effective/total).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

        return OrderReportVO.builder()
                .dateList(StringUtils.join(localDates,","))
                .orderCountList(StringUtils.join(orderCountList,","))
                .validOrderCountList(StringUtils.join(validOrderCountList,","))
                .totalOrderCount(total)
                .validOrderCount(effective)
                .orderCompletionRate(CompletionRate)
                .build();
    }

    /**
     * SalesTop10ReportVO
     * 菜品详情套餐排行榜top10
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        //设置begin和end的开始和结束时间
        //设置当天开始日期和结束日期
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        //查询近7天的数据和菜品去返回
        List<GoodsSalesDTO> goodsSalesDTOS = ordersMapper.selectOredersDetailTop10(beginTime,endTime);
        //获取里面的每个菜品名称和数量
        List<String> nameList = new ArrayList<>();
        List<Integer> numberList = new ArrayList<>();

        for (GoodsSalesDTO goodsSalesDTO : goodsSalesDTOS) {
            nameList.add(goodsSalesDTO.getName());
            numberList.add(goodsSalesDTO.getNumber());
        }
        return new SalesTop10ReportVO(StringUtils.join(nameList,","),StringUtils.join(numberList,","));
    }

    /**
     * 导出运营数据的报表
     * @param response
     */
    @Autowired
    private WorkspaceServiceImpl workspaceServiceImpl;
    @Override
    public void exportBusinessData(HttpServletResponse response) {
        /**导出近30天的运营数据报表
         * @param response
         **/
        //开始时间
        LocalDateTime begin = LocalDateTime.of(LocalDate.now(), LocalTime.MIN).minusDays(30);
        //结束时间
        LocalDateTime end = LocalDateTime.of(LocalDate.now(), LocalTime.MAX).minusDays(1);
        //首先查询到我们营业额的所有数据
        //我们来获取近30天的时间数据
        BusinessDataVO businessDataVO = workspaceServiceImpl.businessData(begin,end);

        //创建模版数据
        XSSFWorkbook xssfWorkbook = null;
        //读入文件流
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("运营数据报表模板.xlsx");
        try {
            xssfWorkbook = new XSSFWorkbook(is);
            //根据模版数据，我们先获取第一行的位置，添加时间
            //获取当前模版的页码对象
            XSSFSheet sheet1 = xssfWorkbook.getSheet("Sheet1");
            //根据页码对象在第一行添加时间
            sheet1.getRow(1).getCell(1).setCellValue("开始时间" + begin + "至" + end);
            //在下面几行添加营业额、订单完成率、新增用户数、有效订单、平均客单价
            sheet1.getRow(3).getCell(2).setCellValue(businessDataVO.getTurnover());
            sheet1.getRow(3).getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
            sheet1.getRow(3).getCell(6).setCellValue(businessDataVO.getNewUsers());
            sheet1.getRow(4).getCell(2).setCellValue(businessDataVO.getValidOrderCount());
            sheet1.getRow(4).getCell(4).setCellValue(businessDataVO.getUnitPrice());

            //在excel添加明细数据
            for (int i = 0; i < 30; i++) {
                //设置开始时间添加
                LocalDateTime localDateTime = begin.plusDays(i);
                log.info("这个时间是：{}",localDateTime);
                //获取到当天的开始时间和结束时间
                LocalDateTime endTime = LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MAX);
                log.info("结束时间：{}",endTime);
                BusinessDataVO businessDataVO1 = workspaceServiceImpl.businessData(localDateTime,endTime);
                log.info("数据：{} + i{}",businessDataVO1 ,i);

                sheet1.getRow(7+i).getCell(1).setCellValue(String.valueOf(localDateTime.toLocalDate()));
                sheet1.getRow(7+i).getCell(2).setCellValue(businessDataVO1.getTurnover());
                sheet1.getRow(7+i).getCell(3).setCellValue(businessDataVO1.getValidOrderCount());
                sheet1.getRow(7+i).getCell(4).setCellValue(businessDataVO1.getOrderCompletionRate());
                sheet1.getRow(7+i).getCell(5).setCellValue(businessDataVO1.getUnitPrice());
                sheet1.getRow(7+i).getCell(6).setCellValue(businessDataVO1.getNewUsers());
            }
            //利用网络流进行写出
            ServletOutputStream servletOutputStream = response.getOutputStream();
            xssfWorkbook.write(servletOutputStream);
            servletOutputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            //最后释放流
            try {
                xssfWorkbook.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }


    }

    /**
     * 封装一个map方法，进行复用
     * @param beginTime
     * @param endTime
     * @param status
     * @return
     */
    private List<Orders> getStringObjectMap(LocalDateTime beginTime, LocalDateTime endTime, Integer status)  {
        Map<String ,Object> map = new HashMap<>();
        map.put("beginTime", beginTime);
        map.put("endTime", endTime);
        map.put("status",status);
        List<Orders> orders = ordersMapper.getByMap(map);
        return orders;
    }

    //创建一个集合拼接方法
    public static String pjoin(List arr){
        StringBuilder sb = new StringBuilder();
        for (Object t: arr) {
            if (t == arr.get(arr.size() - 1)) {
                sb.append(t);
            }
            sb.append(t);
            sb.append(",");
        }
        return sb.toString();
    }


}



